eggjs 基于 urllib 内置实现了一个 HttpClient。
https://eggjs.org/zh-cn/core/httpclient.html

app.httpclient,
app.curl(url, options) === app.httpclient.request(url, options);
都需要使用 await 来修饰。

也有 ctx.curl(url, options) 和 ctx.httpclient.request(url, options);


GET（options.method 默认就是 get）
返回值：对象
{
  status：200/302/404/500等
  headers：响应头，值是一个对象，类似 { 'content-type': 'text/html', ... }
  data：响应 body，默认 HttpClient 不会做任何处理，会直接返回 Buffer 类型数据。 一旦设置了 options.dataType，HttpClient 将会根据此参数对 data 进行相应的处理。
}


POST
await ctx.curl('https://httpbin.org/post', {
  // 必须指定 method
  method: 'POST',
  // 通过 contentType 告诉 HttpClient 以 JSON 格式发送
  contentType: 'json',
  data: {
    hello: 'world',
    now: Date.now(),
  },
  // 明确告诉 HttpClient 以 JSON 格式处理返回的响应 body
  dataType: 'json',
});


PUT
与 POST 类似，它更加适合更新数据和替换数据的语义。 除了 method 参数需要设置为 PUT，其他参数几乎跟 POST 一模一样。


DELETE
它通常可以不需要加请求 body，但是 HttpClient 不会限制。
await ctx.curl('https://httpbin.org/delete', {
  // 必须指定 method
  method: 'DELETE',
  // 明确告诉 HttpClient 以 JSON 格式处理响应 body
  dataType: 'json',
});


【Form 表单提交】
1
面向浏览器设计的 Form 表单（不包含文件）提交接口，通常都要求以 content-type: application/x-www-form-urlencoded 的格式提交请求数据。
const result = await ctx.curl('https://httpbin.org/post', {
  // 必须指定 method，支持 POST，PUT 和 DELETE
  method: 'POST',
  // 不需要设置 contentType，HttpClient 会默认以 application/x-www-form-urlencoded 格式发送请求
  data: {
    now: Date.now(),
    foo: 'bar',
  },
  // 明确告诉 HttpClient 以 JSON 格式处理响应 body
  dataType: 'json',
});
ctx.body = result.data.form;
// 响应最终会是类似以下的结果：
// {
//   "foo": "bar",
//   "now": "1483864184348"
// }

2
以 Multipart 方式上传文件
当一个 Form 表单提交包含文件的时候，请求数据格式就必须以 multipart/form-data 进行提交了。 这个时候需要引入 formstream 这个第三方模块来帮助我们生成可以被 HttpClient 消费的 form 对象。
const FormStream = require('formstream');
  const form = new FormStream();
  // 设置普通的 key value
  form.field('foo', 'bar');
  // 上传当前文件本身用于测试
  form.file('file', __filename);

  // 可以继续通过 form.file() 添加更多文件以实现一次性上传多个文件的需求。
  // form.file('file1', file1);
  // form.file('file2', file2);

  const result = await ctx.curl('https://httpbin.org/post', {
    // 必须指定 method，支持 POST，PUT
    method: 'POST',
    // 生成符合 multipart/form-data 要求的请求 headers
    headers: form.headers(),
    // 以 stream 模式提交
    stream: form,
    // 明确告诉 HttpClient 以 JSON 格式处理响应 body
    dataType: 'json',
  });
  ctx.body = result.data.files;
  // 响应最终会是类似以下的结果：
  // {
  //   "file": "'use strict';\n\nconst For...."
  // }

3
以 Stream 方式上传文件
如果服务端支持流式上传，最友好的方式还是直接发送 Stream。 Stream 实际会以 Transfer-Encoding: chunked 传输编码格式发送，这个转换是 HTTP 模块自动实现的。
const fs = require('fs');
const FormStream = require('formstream');
  // 上传当前文件本身用于测试
  const fileStream = fs.createReadStream(__filename);
  // httpbin.org 不支持 stream 模式，使用本地 stream 接口代替
  const url = `${ctx.protocol}://${ctx.host}/stream`;
  const result = await ctx.curl(url, {
    // 必须指定 method，支持 POST，PUT
    method: 'POST',
    // 以 stream 模式提交
    stream: fileStream,
  });
  ctx.status = result.status;
  ctx.set(result.headers);
  ctx.body = result.data;
  // 响应最终会是类似以下的结果：
  // {"streamSize":574}




